package com.example.java_gobang.game;

import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

//这个类表示匹配器，该类负责完成整个匹配功能
//该模块也存在线程安全问题，当不同的线程操作同一个队列的时候，需要加锁
@Component
@Slf4j
public class Matcher {
    //创建三个匹配队列
    private Queue<User> normalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> veryHighQueue = new LinkedList<>();

    @Autowired
    private OnlineUserManager onlineUserManager;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    //把玩家放到匹配队列中
    public void add(User user){
        if(user.getScore() < 2000){
            synchronized (normalQueue){
                normalQueue.offer(user);
                normalQueue.notify();
            }
            log.info("玩家" + user.getUsername() + " 进入normalQueue中");
        } else if (user.getScore() < 3000) {
            synchronized (highQueue){
                highQueue.offer(user);
                highQueue.notify();
            }
            log.info("玩家" + user.getUsername() + " 进入highQueue中");
        } else {
            synchronized (veryHighQueue){
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }
            log.info("玩家" + user.getUsername() + " 进入veryHighQueue中");
        }
    }

    public void remove(User user){
        //当玩家点击停止匹配的时候，将玩家从匹配队列中删除
        if(user.getScore() < 2000){
            synchronized (normalQueue){
                normalQueue.remove(user);
            }
            log.info("玩家" + user.getUsername() + " 移出normalQueue");
        } else if (user.getScore() < 3000) {
            synchronized (highQueue){
                highQueue.remove(user);
            }
            log.info("玩家" + user.getUsername() + " 移出highQueue");
        } else {
            synchronized (veryHighQueue){
                veryHighQueue.remove(user);
            }
            log.info("玩家" + user.getUsername() + " 移出veryHighQueue");
        }
    }

    //创建三个线程分别对这三个队列进行操作
    public Matcher(){
        Thread t1 = new Thread() {
            @Override
            public void run() {
                //扫描normalQueue
                while(true){
                    handlerMatch(normalQueue);
                }
            }
        };
        t1.start();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                //扫描highQueue
                while(true){
                    handlerMatch(highQueue);
                }
            }
        };
        t2.start();
        Thread t3 = new Thread() {
            @Override
            public void run() {
                //扫描veryHighQueue
                while(true){
                    handlerMatch(veryHighQueue);
                }
            }
        };
        t3.start();
    }

    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue){
            try{
                //队列的初始情况可能是空，往队列中添加一个元素，此时仍然不能进行后续的匹配
                while (matchQueue.size() < 2){
                    matchQueue.wait();
                }
                //1.从队列中取出两个元素然后组成房间
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                log.info("两个玩家成功匹配：player1: " + player1.getUsername() + " player2: " + player2.getUsername());
                //2.获取到玩家的websocket的session，为了告诉玩家，你排到了
                WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());
                //理论上来说匹配队列中的玩家一定是在线的状态
                //因为前面的逻辑中进行了处理，当玩家断开链接的时候从匹配队列中移除
                //此处仍然进行一次判定
                if(session1 == null){
                    //将玩家2重新放回到匹配队列中
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null){
                    matchQueue.offer(player1);
                    return;
                }
                //理论上也不会存在，为提高代码健壮性而写，防止因为出现某些特别的bug而导致严重的错误
                if(session1 == session2){
                    matchQueue.offer(player1);
                    return;
                }
                //4. 将两个玩家放到一个游戏房间中
                Room room = new Room();
                //暂时不放到房间中，先看用户是否能连接到游戏房间
//                room.setUser1((User)session1.getAttributes().get("user"));
//                room.setUser2((User)session2.getAttributes().get("user"));
                roomManager.add(room, player1.getUserId(), player2.getUserId());
                //5.给前端反馈信息，你匹配到了
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setMessage("matchSuccess");
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
